<template>
  <transition name="grimm-picker-fade">
    <GrimmPopup
      class="grimm-picker"
      v-show="isVisible"
      position="bottom"
      type="picker"
      :mask="true"
      :center="false"
      :zIndex="100"
      @mask-click="maskClick"
      @touchmove="e => e.preventDefault()"
    >
      <transition name="grimm-picker-move">
        <div class="grimm-picker-panel grimm-safe-area-pb">
          <div class="grimm-picker-choose border-bottom-1px">
            <span class="grimm-picker-cancel" @click="cancel">{{_cancelTxt}}</span>
            <span class="grimm-picker-confirm" @click="confirm">{{_confirmTxt}}</span>
            <div class="grimm-picker-title-group">
              <h1 class="grimm-picker-title">{{title}}</h1>
              <h1 class="grimm-picker-subtitle" v-if="subtitle">{{subtitle}}</h1>
            </div>
          </div>

          <div class="grimm-picker-content">
            <i class="border-bottom-1px"></i>
            <i class="border-center-1px"></i>
            <i class="border-top-1px"></i>
            <div class="grimm-picker-wheel-wrapper" ref="wheelWrapper">
              <template v-for="(item, index) in finalData">
                <div :style="{order: _getFlexOrder(item)}" :key="index">
                  <ul class="grimm-picker-wheel-scroll">
                    <li
                      class="grimm-picker-wheel-item"
                      v-for="(itemChild, indexChild) in item"
                      :key="indexChild"
                    >{{itemChild[textKey]}}</li>
                  </ul>
                </div>
              </template>
            </div>
          </div>
        </div>
      </transition>
    </GrimmPopup>
  </transition>
</template>
<script>
import GrimmPopup from '../Popup/index.vue';
import BScroll from 'better-scroll';
import visibilityMixin from '../../common/mixins/visibility';
import popupMixin from '../../common/mixins/popup';
import basicPickerMixin from '../../common/mixins/basic-picker';
import pickerMixin from '../../common/mixins/picker';
const name = 'grimm-picker';
const EVENT_SELECT = 'select';
const EVENT_VALUE_CHANGE = 'value-change';
const EVENT_CANCEL = 'cancel';
const EVENT_CHANGE = 'change';

export default {
  name,
  components: { GrimmPopup },
  mixins: [visibilityMixin, popupMixin, basicPickerMixin, pickerMixin],
  props: {
    pending: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      finalData: this.data.slice(),
    };
  },
  created() {
    this._values = [];
    this._indexes = this.selectedIndex;
  },
  methods: {
    confirm() {
      if (!this._canConfirm()) {
        return;
      }
      this.hide();

      let changed = false;
      let pickerSelectedText = [];

      const { length } = this.finalData;
      const oldLength = this._values.length;

      // when column count has changed.
      if (oldLength !== length) {
        changed = true;
        oldLength > length && (this._values.length = this._indexes.length = length);
      }

      for (let i = 0; i < length; i++) {
        let index = this.wheels[i].getSelectedIndex();
        this._indexes[i] = index;

        let value = null;
        let text = '';
        if (this.finalData[i].length) {
          value = this.finalData[i][index][this.valueKey];
          text = this.finalData[i][index][this.textKey];
        }
        if (this._values[i] !== value) {
          changed = true;
        }
        this._values[i] = value;
        pickerSelectedText[i] = { value, text };
      }

      this.$emit(EVENT_SELECT, this._values, this._indexes, pickerSelectedText);

      if (changed) {
        this.$emit(EVENT_VALUE_CHANGE, this._values, this._indexes, pickerSelectedText);
      }
    },
    maskClick() {
      this.maskClosable && this.cancel();
    },
    cancel() {
      this.hide();
      this.$emit(EVENT_CANCEL);
    },
    show() {
      if (this.isVisible) {
        return;
      }

      this.isVisible = true;
      if (!this.wheels || this.dirty) {
        this.$nextTick(() => {
          this.wheels = this.wheels || [];
          let { wheelWrapper } = this.$refs;
          for (let i = 0; i < this.finalData.length; i++) {
            this._createWheel(wheelWrapper, i).enable();
            this.wheels[i].wheelTo(this._indexes[i]);
          }
          this.dirty && this._destroyExtraWheels();
          this.dirty = false;
        });
      } else {
        for (let i = 0; i < this.finalData.length; i++) {
          this.wheels[i].enable();
          this.wheels[i].wheelTo(this._indexes[i]);
        }
      }
    },
    hide() {
      if (!this.isVisible) {
        return;
      }
      this.isVisible = false;

      for (let i = 0; i < this.finalData.length; i++) {
        this.wheels[i].disable();
      }
    },
    setData(data, selectedIndex) {
      this._indexes = selectedIndex ? [...selectedIndex] : [];
      this.finalData = data.slice();
      if (this.isVisible) {
        this.$nextTick(() => {
          const { wheelWrapper } = this.$refs;
          this.finalData.forEach((item, i) => {
            this._createWheel(wheelWrapper, i);
            this.wheels[i].wheelTo(this._indexes[i]);
          });
          this._destroyExtraWheels();
        });
      } else {
        this.dirty = true;
      }
    },
    refill(datas) {
      let ret = [];
      if (!datas.length) {
        return ret;
      }
      datas.forEach((data, index) => {
        ret[index] = this.refillColumn(index, data);
      });
      return ret;
    },
    refillColumn(index, data) {
      const { wheelWrapper } = this.$refs;
      let scroll = wheelWrapper.children[index].querySelector('.grimm-picker-wheel-scroll');
      let wheel = this.wheels ? this.wheels[index] : false;
      let dist = 0;
      if (scroll && wheel) {
        let oldData = this.finalData[index];
        this.$set(this.finalData, index, data);
        let selectedIndex = wheel.getSelectedIndex();
        if (oldData.length) {
          let oldValue = oldData[selectedIndex][this.valueKey];
          for (let i = 0; i < data.length; i++) {
            if (data[i][this.valueKey] === oldValue) {
              dist = i;
              break;
            }
          }
        }
        this._indexes[index] = dist;
        this.$nextTick(() => {
          wheel = this._createWheel(wheelWrapper, index);
          wheel.wheelTo(dist);
        });
      }
      return dist;
    },
    scrollTo(index, dist) {
      const wheel = this.wheels[index];
      this._indexes[index] = dist;
      wheel.wheelTo(dist);
    },
    refresh() {
      this.$nextTick(() => {
        this.wheels.forEach(wheel => {
          wheel.refresh();
        });
      });
    },
    _createWheel(wheelWrapper, i) {
      if (!this.wheels[i]) {
        const wheel = (this.wheels[i] = new BScroll(wheelWrapper.children[i], {
          wheel: {
            selectedIndex: this._indexes[i] || 0,
            wheelWrapperClass: 'grimm-picker-wheel-scroll',
            wheelItemClass: 'grimm-picker-wheel-item',
          },
          swipeTime: this.swipeTime,
          observeDOM: false,
        }));
        wheel.on('scrollEnd', () => {
          this.$emit(EVENT_CHANGE, i, wheel.getSelectedIndex());
        });
      } else {
        this.wheels[i].refresh();
      }
      return this.wheels[i];
    },
    _destroyExtraWheels() {
      const dataLength = this.finalData.length;
      if (this.wheels.length > dataLength) {
        const extraWheels = this.wheels.splice(dataLength);
        extraWheels.forEach(wheel => {
          wheel.destroy();
        });
      }
    },
    _canConfirm() {
      return (
        !this.pending &&
        this.wheels.every(wheel => {
          return !wheel.isInTransition;
        })
      );
    },
    _getFlexOrder(data) {
      if (data[0]) {
        return data[0][this.orderKey];
      }
      return 0;
    },
  },
  beforeDestroy() {
    this.wheels &&
      this.wheels.forEach(wheel => {
        wheel.destroy();
      });
    this.wheels = null;
  },
};
</script>